/*
 * =====================================================================================
 *
 *       Filename:  netBuffer.h
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  07/13/2012 02:54:20 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  wangtengchao , wangtengchao AT gmail.com
 *   Organization:  
 *
 * =====================================================================================
 */
#ifndef NETBUFFER_H
#define NETBUFFER_H
#include<vector>
#include<string>
#include<sys/types.h>//for ssize_t
namespace inm
{
	namespace net
	{
		//the reason of fixing the size of buffer 
        //vector is not a sequent memory address.in readv,we need a sequent array
        static const size_t InitialBufferSize = 1024;
        static const size_t InitialPrependSize = 8;
		//a buffer used in tcp connection
        class NetBuffer //may be copyable   descide later
		{
			public:
				NetBuffer():
                    buffer_(InitialPrependSize + InitialBufferSize),
                    readIndex_(InitialPrependSize),
                    writeIndex_(InitialPrependSize)
                    {};
				//user use
                ssize_t readFromFd(int fd);
				//write to buffer
                void append(const std::string& str)
				{
                    append(str.data(),str.length());
				}
                void append(const char* data,size_t num);

				void shrink();//user call

                std::string readAndRetrive(size_t len)
                {//readIndex_ will change

                    if(len <= readableNum())
                    {
                        readIndex_ += len;
                        return std::string(&buffer_[readIndex_-len],&buffer_[readIndex_]);
                    }
                    return "";//not enough write log
                }
                void retrive(size_t len)
                {//don't construct string compared to readAndRetrive
                    if(len <= readableNum())
                    readIndex_ += len;
                }

                std::string toString()
                {//get buffer actual content as string  ,not including head
                    if(0 < readableNum())
                        return std::string(&buffer_[readIndex_],&buffer_[writeIndex_]);
                    return "";
                }
                const std::string toString() const
                {
                    if(0 < readableNum())
                        return std::string(&buffer_[readIndex_],&buffer_[writeIndex_]);
                    return "";
                }
                //for test
                size_t getBufferSize()
				{
					return buffer_.size();
				}	
                size_t getContentSize()
                {
                    return buffer_.size()-InitialPrependSize;//remove the head size
                }
                char* peek(){return &buffer_[readIndex_];}
                //can prepend more than once until header is full
                int prepend(const std::string& str)
                {
                    return prepend(str.data(),str.length());
                }

                int prepend(const void* data,size_t len);//prepend data to the buffer


                size_t readableNum(){ return writeIndex_ - readIndex_;}
                size_t readableNum() const {return writeIndex_ - readIndex_;}
			private:
				//internal call

                size_t _writeableNum(){ return buffer_.size()- writeIndex_;};//use size or capacity?
				char* _writeBegin() //return value is char*  not size_t or ssize_t
				{//get the pointer of the write begin location
					return & buffer_[writeIndex_];
				}	
                const char* _writeBegin() const
                {
                    return & buffer_[writeIndex_];
                }
				char* _begin()
				{//get the beigin pointer of vector
					return &(*buffer_.begin());
				}
                char* _beginWithoutHead()
                {
                    return &(*(buffer_.begin()+InitialPrependSize));
                }

				//override function 
				void _expandAndWrite(const char* data,size_t num);
				void _expandAndWrite(const std::string& str)
				{
					_expandAndWrite(str.data(),str.length());//str.c_str?
				}
				void _moveToFront();
                size_t _prependable(){return readIndex_;}
                std::vector<char> buffer_;//vector already  have good performance
				size_t readIndex_;//point to the begin location info can be read
                size_t writeIndex_;//point to the first location can be written


		};
	};
};

#endif
